﻿/************************************************************************

 This file is part of "10 Second Tim".

 "10 Second Tim" is free software: you can redistribute it and/or modify
 it under the terms of the GNU General Public License as published by
 the Free Software Foundation, either version 3 of the License, or
 (at your option) any later version.

 "10 Second Tim" is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of
 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 GNU General Public License for more details.

 You should have received a copy of the GNU General Public License
 along with "10 Second Tim".  If not, see <http://www.gnu.org/licenses/>.

************************************************************************/

// All code (c)2013 Scott Bevin. all rights reserved

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using LDE;
using LDE.Input;
using LudumDare27.Games.Game_1;
using LudumDare27.GameScreens;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace LudumDare27.Games.Game_4
{
	public class GameplayScreen : GameScreen
	{
		public static bool PlayedYet = false;

		private Camera m_cam;
		private SpriteFont levelInfoFont;

		public Character m_playerchar = null;

		private Terrain m_terrain = null;

		private InputTrigger m_jumpInput = new InputTrigger( "Jump" );
		private InputTrigger m_slideInput = new InputTrigger( "Slide" );

		private WhiteFadeScreen whiteFadeScreen = null;

		private ScreenBorder border;

		private float levelTimer = 0.0f;

		private SoundEffect whiteNoiseSfx;
		private SoundEffectInstance whiteNoiseSfxInstance;
		private SoundEffect newLevelSfx;

		public class Box
		{
			public bool Visible = true;
			public bool Reflected = false;
			public Sprite sprite;
			public Vector2 Pos;
			public Vector2 Velocity;
			public float Rotation;

			public Box( ContentManager content )
			{
				sprite = new Sprite( content.Load<Texture2D>( "Img/Box" ), 1 );
			}
		}

		public List<Box> m_boxes = new List<Box>( );

		public int Level;
		private float camExtrarot = 0.0f;

		public GameplayScreen( int level )
			: base( true )
		{
			Level = level;
		}

		private Song backgroundMusic;

		override public void OnAdded( )
		{
			backgroundMusic = ( (LD27Game)Game ).PickSong( ContentManager );
			MediaPlayer.Play( backgroundMusic );
			MediaPlayer.IsRepeating = true;
			border = new ScreenBorder( ContentManager );
			levelInfoFont = ContentManager.Load<SpriteFont>( "Fonts/DebugFont" );
			Random rnd = new Random( );
			whiteNoiseSfx = ContentManager.Load<SoundEffect>( "Sfx/AboutToTrans" );
			whiteNoiseSfxInstance = whiteNoiseSfx.CreateInstance( );
			whiteNoiseSfxInstance.IsLooped = true;
			whiteNoiseSfxInstance.Play( );

			newLevelSfx = ContentManager.Load<SoundEffect>( "Sfx/NewLevel" );
			newLevelSfx.Play( );

			m_cam = new Camera( Game.GraphicsDevice.PresentationParameters.BackBufferWidth,
				Game.GraphicsDevice.PresentationParameters.BackBufferHeight );
			m_cam.Zoom = 0.5f;
			m_cam.Zoom += (float)rnd.NextDouble( ) * 0.1f * ( Level );

			m_cam.Rotation = m_cam.TargetRotation = (float)( ( ( Math.PI * 2.0f ) - ( ( Math.PI * 2.0f ) / ( Level ) ) ) * rnd.NextDouble( ) );

			m_playerchar = new Character( ContentManager.Load<Texture2D>( "Img/Chars/Garry" ), ContentManager );

			// provide constant grav
			m_playerchar.Acceleration.Y = Defs.Game4.Gravity;

			m_cam.Position = m_cam.TargetPosition = m_playerchar.Position;

			m_terrain = new Terrain( this, 20, Defs.Game4.TileWidth, false );

			// Now hack the tiles
			for ( int i = 0; i < 2; ++i )
			{
				m_terrain.m_tiles[ i ] = new Pit( ContentManager, m_terrain.m_tiles[ i ].Pos );
			}

			for ( int i = 18; i < 20; ++i )
			{
				m_terrain.m_tiles[ i ] = new Pit( ContentManager, m_terrain.m_tiles[ i ].Pos );
			}

			m_terrain.m_tiles[ 2 ] = new EndPit( ContentManager, m_terrain.m_tiles[ 2 ].Pos );
			m_terrain.m_tiles[ 19 ] = new StartPit( ContentManager, m_terrain.m_tiles[ 19 ].Pos );

			int ifff = 5;

			while ( !( m_terrain.m_tiles[ ifff ] is NormalTile ) )
			{
				++ifff;
			}

			m_playerchar.Position.X = m_terrain.m_tiles[ ifff ].Pos.X;
			m_terrain.m_tiles[ ifff ] = new NormalTile( ContentManager, m_terrain.m_tiles[ ifff ].Pos );

			m_cam.Position = m_cam.TargetPosition = m_playerchar.Position;

			m_jumpInput.Add( Buttons.A ).Add( Keys.W ).Add( Keys.Up ).Add( Keys.Space );
			m_slideInput.Add( Buttons.X ).Add( Keys.S ).Add( Keys.Down ).Add( Keys.LeftControl );

			if ( Level > 10 )
				camExtrarot = ( (float)rnd.NextDouble( ) * 2.0f ) - 1.0f * ( (float)Math.PI * 0.01f * ( Level ) );

			if ( rnd.Next( 100 ) < 50 )
				camExtrarot = -camExtrarot;

			float worldWidth = 20 * Defs.Game4.TileWidth;

			int numBoxes = Level * Defs.Game4.LevelBoxMult;

#if SILVERLIGHT
			if( numBoxes > 200 )
			numBoxes = 200;
#endif

			float dist = ( 1000.0f );
			float angle = (float)( Math.PI * 2.0f * rnd.NextDouble( ) );

			for ( int i = 0; i < numBoxes; ++i )
			{
				for ( int j = 0; j < Level; ++j )
				{
					Box newBox = new Box( ContentManager );
					angle += (float)( Math.PI * 0.2f * rnd.NextDouble( ) );

					newBox.Rotation = angle;
					newBox.Pos.X = worldWidth * (float)rnd.NextDouble( );
					newBox.Pos.Y = -dist;

					newBox.Velocity.X = 0.0f;
					newBox.Velocity.Y = Defs.Game4.Gravity * 0.5f;

					m_boxes.Add( newBox );
				}

				dist += ( 2000.0f / Math.Min( Level, 2 ) ) * (float)rnd.NextDouble( );
			}

			if ( !PlayedYet )
			{
				m_cam.Rotation = m_cam.TargetRotation = 0.0f;
				m_cam.Zoom = 0.5f;
				camExtrarot = 0.0f;
			}
			base.OnAdded( );
		}

		override public void Update( float dt )
		{
			if ( m_playerchar.Dead )
				levelTimer = 0.0f;

			levelTimer += dt;

			InputHandler input = Player.Get.GetInput( this );
			whiteNoiseSfxInstance.Volume = 0.0f;
			if ( levelTimer > 3.0f )
			{
				whiteNoiseSfxInstance.Volume = MathHelper.Clamp( 1.0f - ( ( 10.0f - levelTimer ) / 3.0f ), 0.0f, 1.0f );
			}
			if ( levelTimer < 9.5f )
			{
				if ( input != null && !m_playerchar.Dead )
				{
					if ( input.IsPressed( m_jumpInput ) != null )
					{
						m_playerchar.Jump( );
					}

					if ( input.IsPressed( m_slideInput ) != null )
					{
						m_playerchar.Slide( );
					}

					m_playerchar.Velocity.X = input.GetStickVals( ).X * Defs.Game4.BaseMoveSpeed;
				}

				m_playerchar.Update( dt, m_playerchar.Dead ? 1000.0f : m_terrain.GetGroundHeight( m_playerchar ), false );

				for ( int i = 0; i < m_boxes.Count; ++i )
				{
					Box b = m_boxes[ i ];

					b.Pos += b.Velocity * dt;
					b.Rotation += (float)( Math.PI * dt );

					if ( Math.Abs( b.Pos.Y - m_playerchar.Position.Y ) < m_playerchar.m_sprite.origin.Y + b.sprite.origin.Y &&
						Math.Abs( b.Pos.X - m_playerchar.Position.X ) < m_playerchar.m_sprite.origin.X + b.sprite.origin.X )
					{
						m_playerchar.Kill( );
						m_playerchar.Velocity = Vector2.Zero;
						m_playerchar.Velocity.Y = -360.0f;
					}
				}

				if ( !m_playerchar.Dead )
				{
					m_cam.TargetPosition = m_playerchar.Position;

					m_cam.Rotation += camExtrarot * dt;
					m_cam.TargetRotation = m_cam.Rotation;
				}

				m_cam.Update( dt );

				if ( !m_terrain.CharSafe( m_playerchar ) || m_playerchar.Dead )
				{
					if ( !m_playerchar.Dead )
					{
						m_playerchar.Kill( );
						m_playerchar.Velocity = Vector2.Zero;
						m_playerchar.Velocity.Y = -360.0f;
					}
					else if ( m_playerchar.Position.Y > 300.0f )
					{
						if ( whiteFadeScreen == null )
						{
							whiteFadeScreen = new WhiteFadeScreen( );
							GameScreenManager.AddGameScreen( whiteFadeScreen, null, GameScreenManager.AddGameScreenData.PositioningOptions.OnTop );
						}
					}
				}
			}
			else
			{
				if ( whiteFadeScreen == null )
				{
					whiteFadeScreen = new WhiteFadeScreen( );
					GameScreenManager.AddGameScreen( whiteFadeScreen, null, GameScreenManager.AddGameScreenData.PositioningOptions.OnTop );
				}
			}

			if ( whiteFadeScreen != null && whiteFadeScreen.State == WhiteFadeScreen.States.FadedIn )
			{
				whiteFadeScreen.FadeOut( );

				if ( m_playerchar.Dead )
					GameScreenManager.AddGameScreen( new GameOverScreen( Level, false ), whiteFadeScreen, GameScreenManager.AddGameScreenData.PositioningOptions.BelowRef );
				else
					GameScreenManager.AddGameScreen( ( (LD27Game)Game ).ChooseNextGame( this, Level + 1 ), whiteFadeScreen, GameScreenManager.AddGameScreenData.PositioningOptions.BelowRef );

				this.KillScreen = true;
			}

			base.Update( dt );
		}

		override public void Render( float dt, GraphicsDevice gd, SpriteBatch sprites )
		{
			sprites.Begin( SpriteSortMode.Deferred, BlendState.NonPremultiplied, null, null, null, null, m_cam.GetWorldMatrix( ) );

			m_terrain.Render( sprites, m_playerchar );
			m_playerchar.Render( sprites );

			foreach ( Box b in m_boxes )
			{
				if ( b.Visible )
					b.sprite.Render( sprites, b.Pos, b.Rotation );
			}

			sprites.End( );
			border.Render( gd, sprites );

			sprites.Begin( );

			InputHandler input = Player.Get.GetInput( this );

			if ( input != null && !PlayedYet )
			{
				string str = "";

				if ( input.FindDevice( GamePadInputDevice.DeviceTypeId, -1 ) != null )
				{
					str = "Jump: A - Slide: X - Left Stick: Left / Right [Avoid the boxes]";
				}
				else
				{
					str = "Jump: Up Arrow - Slide: Down Arrow - Arrows: Left / Right [Avoid the boxes]";
				}

				sprites.DrawString( levelInfoFont, str, new Vector2( Game.GraphicsDevice.PresentationParameters.BackBufferWidth * 0.5f, Game.GraphicsDevice.PresentationParameters.BackBufferHeight * 0.9f ),
					Color.Black, 0.0f, levelInfoFont.MeasureString( str ) * 0.5f, 1.0f, SpriteEffects.None, 1.0f );
			}

			sprites.End( );

			base.Render( dt, gd, sprites );
		}

		override public void OnRemoved( )
		{
			PlayedYet = true;

#if SILVERLIGHT
			whiteNoiseSfxInstance.Stop(  );
#else
			whiteNoiseSfxInstance.Stop( true );
#endif
			base.OnRemoved( );
		}
	}
}